#include "cem/material_database.h"
#include "cem/material_law.h"
#include "cem/electromagnetics_system.h"
#include "cem/parameter_reader.h"

#include <libmesh/mesh_base.h>
#include <libmesh/equation_systems.h>
#include <libmesh/elem.h>

namespace cem
{

// 函数: add_material
void
MaterialDatabase::add_material(const std::string & name, const Material & mat)
{
    _materials[name] = mat;
}

// 函数: find_material
const Material *
MaterialDatabase::find_material(const std::string & name) const
{
    if (auto it = _materials.find(name); it != _materials.end())
        return &it->second;
    return nullptr;
}

// 函数: initialize
// 作用: 设置材料律（若为空则使用 LegacyMapMaterialLaw）并刷新子域张量缓存
void
MaterialDatabase::initialize(const ElectromagneticsSystem & system,
                             std::unique_ptr<MaterialLaw> law)
{
    if (!law)
        _law = std::make_unique<LegacyMapMaterialLaw>();
    else
        _law = std::move(law);

    refresh_cache_for_mesh(system);
}

// 函数: initialize
// 作用: 从参数读取区域映射与各向异性设置，随后初始化材料律并构建缓存
void
MaterialDatabase::initialize(const ElectromagneticsSystem & system,
                             const ParameterReader & params,
                             std::unique_ptr<MaterialLaw> law)
{
    // 注入区域标量映射
    set_area_epsl_map(params.area_epsl_map());
    set_area_cond_map(params.area_cond_map());
    set_area_mu_map(params.area_mu_map());

    // 注入各向异性规格
    set_area_aniso_conductivity(params.area_aniso_conductivity());
    set_area_aniso_magnetic(params.area_aniso_magnetic());
    set_area_aniso_dielectric(params.area_aniso_dielectric());

    // 委托至已有 initialize 实现，完成材料律设置与缓存构建
    initialize(system, std::move(law));
}

// 函数: refresh_cache_for_mesh
// 作用: 扫描网格子域并根据材料律填充 σ、ε、μ^{-1} 张量缓存
void
MaterialDatabase::refresh_cache_for_mesh(const ElectromagneticsSystem & system)
{
    _cache.clear();

    const libMesh::MeshBase & mesh = system.equation_systems().get_mesh();
    auto & subdomains = mesh.get_mesh_subdomains();

    for (int sid : subdomains)
    {
        MaterialTensors mt;
        mt.sigma  = _law->get_sigma_tensor(sid, system);
        mt.epsl   = _law->get_epsl_tensor(sid, system);
        mt.inv_mu = _law->get_inv_mu_tensor(sid, system);
        _cache[sid] = mt;
    }
}

// 函数: set_material_law
// 作用: 切换材料律实现并重建缓存
void
MaterialDatabase::set_material_law(const ElectromagneticsSystem & system,
                                   std::unique_ptr<MaterialLaw> law)
{
    _law = std::move(law);
    refresh_cache_for_mesh(system);
}

// 函数: get_sigma_tensor
// 作用: 读取子域的电导率张量 σ
const std::array<std::array<double, 3>, 3> &
MaterialDatabase::get_sigma_tensor(int subdomain_id) const
{
    return _cache.at(subdomain_id).sigma;
}

// 函数: get_epsl_tensor
// 作用: 读取子域的介电常数张量 ε
const std::array<std::array<double, 3>, 3> &
MaterialDatabase::get_epsl_tensor(int subdomain_id) const
{
    return _cache.at(subdomain_id).epsl;
}

// 函数: get_inv_mu_tensor
// 作用: 读取子域的磁导率逆张量 μ^{-1}
const std::array<std::array<double, 3>, 3> &
MaterialDatabase::get_inv_mu_tensor(int subdomain_id) const
{
    return _cache.at(subdomain_id).inv_mu;
}

// 函数: has_subdomain
// 作用: 查询缓存中是否包含该子域 id
bool
MaterialDatabase::has_subdomain(int subdomain_id) const
{
    return _cache.find(subdomain_id) != _cache.end();
}

} // namespace cem